import json
import requests
from datetime import datetime

from test_reports.models import TestReports, ReportDescribe
from common.get_log import GetLog
global_session = requests.Session()
logging = GetLog.get_logger()

def run_test_case(name, test_case, session):
    # 解析测试用例
    method = test_case.get("method")
    url = test_case.get("url")
    headers = test_case.get("headers")
    params = test_case.get("params")
    body_type = test_case.get("body_type")
    body = test_case.get("body")
    is_assert = test_case.get("is_assert")
    assert_type = test_case.get("assert_type")
    assert_body = test_case.get("assert_body")
    logging.info(f"method:{method}, url：{url}，headers：{headers}，params：{params}，body_type：{body_type}，body：{body}，is_assert：{is_assert}，"
                 f"assert_type：{assert_type}，assert_body：{assert_body}")
    # 执行 HTTP 请求
    response = None
    error_msg = ""  # 保存异常信息
    try:
        if method.upper() == "GET":
            response = session.get(url, headers=headers, params=params)
            logging.info(f"请求为：{method.upper()}, reponse：{response.text}")
        elif method.upper() == "POST":
            if body_type == 2:
                response = session.post(url, headers=headers, params=params, json=body)
            else:
                response = session.post(url, headers=headers, params=params, data=body)
            logging.info(f"请求为：{method.upper()}, reponse：{response.text}")
    except Exception as e:
        error_msg = f"ERROR: {e}"  # 保存异常信息
        logging.error(f"{name}ERROR: {e}")
        return None, error_msg  # 请求出现异常

    # 处理 HTTP 响应和断言
    fail_reason = ""  # 保存失败原因
    if is_assert and response:  # 只处理能够断言的响应
        if assert_type == 2:  # 检查状态码
            if response.status_code == int(assert_body):
                logging.info(f"状态码：{response.status_code}，断言成功")
                return True, ""  # 请求成功，无异常信息和失败原因
            else:
                fail_reason = f"FAIL: status code {response.status_code}"  # 保存失败原因
                logging.info(f"FAIL: status code {response.status_code}")
                return False, fail_reason  # 断言失败，返回失败标志和失败原因
        elif assert_type == 1:  # 检查响应内容
            if assert_body in response.text:
                logging.info(f"响应内容： {response.text}，断言成功")
                return True, ""  # 请求成功，无异常信息和失败原因
            else:
                fail_reason = f"response body does not contain '{assert_body}'"  # 保存失败原因
                logging.info(f"响应内容： {response.text} does not contain '{assert_body}， 断言失败")
                return False, fail_reason  # 断言失败，返回失败标志和失败原因
    else:
        return True, ""  # 没有断言，请求成功，返回成功标志和空字符串
    logging.info(f"请求无响应内容，返回空结果和空字符串")
    return None, ""  # 请求无响应内容，返回空结果和空字符串


def run_test_cases(test_cases_file, report_id):
    with open(test_cases_file, "r",  encoding="utf-8") as f:
        test_cases = json.load(f)

    start_time = datetime.now()  # 记录开始时间
    total_cases = len(test_cases)  # 记录总测试用例数
    success_cases = 0  # 记录成功测试用例数
    error_cases = 0  # 记录发生错误的测试用例数（包括 HTTP 请求错误和断言错误）
    fail_cases = 0  # 记录执行失败的测试用例数
    session = global_session  # 使用全局 session
    logs = []   # 记录所有的日志信息，包括成功、错误和失败
    for name, test_case in test_cases.items():
        result, log = run_test_case(name, test_case, session)
        if result is None:  # 执行出错的测试用例
            error_cases += 1
            logs.append((name, 2, log))
        elif not result:  # 执行失败的测试用例
            fail_cases += 1
            logs.append((name, 1, log))
        else:  # 执行成功的测试用例
            success_cases += 1
            logs.append((name, 0, ""))

    end_time = datetime.now()  # 记录结束时间
    duration = end_time - start_time  # 计算测试持续时间
    logging.info(f"总测试用例数：{total_cases}")
    logging.info(f"执行成功的测试用例数：{success_cases}")
    logging.info(f"执行错误的测试用例数（包括 HTTP 请求错误和断言错误）：{error_cases}")
    logging.info(f"执行失败的测试用例数：{fail_cases}")
    logging.info(f"测试持续时间：{duration}")
    test_report = TestReports.objects.filter(id=report_id).first()
    test_report.test_all_count = total_cases
    test_report.success_count = success_cases
    test_report.failure_count = fail_cases
    test_report.error_count = error_cases
    try:
        test_report.pass_rate = round((test_report.success_count / test_report.test_all_count) * 100, 2)
    except ZeroDivisionError:
        test_report.pass_rate = 0
    test_report.startTime = start_time
    test_report.stopTime = end_time
    test_report.status = 1
    test_report.save()
    for result in logs:
        report_describe = ReportDescribe(name=result[0], error_msg=result[2], status=result[1], test_report=test_report)
        report_describe.save()
